free_xenheap_page(d->shared_info);
}
+void arch_domain_shutdown(struct domain *d)
+{
+}
+
+void arch_domain_pause(struct domain *d)
+{
+}
+
+void arch_domain_unpause(struct domain *d)
+{
+}
+
static int is_guest_pv32_psr(uint32_t psr)
{
switch (psr & PSR_MODE_MASK)
#include <asm/fixmap.h>
#include <asm/hvm/hvm.h>
#include <asm/hvm/support.h>
+#include <asm/hvm/viridian.h>
#include <asm/debugreg.h>
#include <asm/msr.h>
#include <asm/traps.h>
psr_free_rmid(d);
}
+void arch_domain_shutdown(struct domain *d)
+{
+ if ( has_viridian_time_ref_count(d) )
+ viridian_time_ref_count_freeze(d);
+}
+
+void arch_domain_pause(struct domain *d)
+{
+ if ( has_viridian_time_ref_count(d) )
+ viridian_time_ref_count_freeze(d);
+}
+
+void arch_domain_unpause(struct domain *d)
+{
+ if ( has_viridian_time_ref_count(d) )
+ viridian_time_ref_count_thaw(d);
+}
+
unsigned long pv_guest_cr4_fixup(const struct vcpu *v, unsigned long guest_cr4)
{
unsigned long hv_cr4_mask, hv_cr4 = real_cr4_to_pv_guest_cr4(read_cr4());
return 1;
}
+static int64_t raw_trc_val(struct domain *d)
+{
+ uint64_t tsc;
+ struct time_scale tsc_to_ns;
+
+ tsc = hvm_get_guest_tsc(pt_global_vcpu_target(d));
+
+ /* convert tsc to count of 100ns periods */
+ set_time_scale(&tsc_to_ns, d->arch.tsc_khz * 1000ul);
+ return scale_delta(tsc, &tsc_to_ns) / 100ul;
+}
+
+void viridian_time_ref_count_freeze(struct domain *d)
+{
+ struct viridian_time_ref_count *trc;
+
+ trc = &d->arch.hvm_domain.viridian.time_ref_count;
+
+ if ( test_and_clear_bit(_TRC_running, &trc->flags) )
+ trc->val = raw_trc_val(d) + trc->off;
+}
+
+void viridian_time_ref_count_thaw(struct domain *d)
+{
+ struct viridian_time_ref_count *trc;
+
+ trc = &d->arch.hvm_domain.viridian.time_ref_count;
+
+ if ( !d->is_shutting_down &&
+ !test_and_set_bit(_TRC_running, &trc->flags) )
+ trc->off = (int64_t)trc->val - raw_trc_val(d);
+}
+
int rdmsr_viridian_regs(uint32_t idx, uint64_t *val)
{
struct vcpu *v = current;
case VIRIDIAN_MSR_TIME_REF_COUNT:
{
- uint64_t tsc;
- struct time_scale tsc_to_ns;
+ struct viridian_time_ref_count *trc;
+
+ trc = &d->arch.hvm_domain.viridian.time_ref_count;
if ( !(viridian_feature_mask(d) & HVMPV_time_ref_count) )
return 0;
- perfc_incr(mshv_rdmsr_time_ref_count);
- tsc = hvm_get_guest_tsc(pt_global_vcpu_target(d));
+ if ( !test_and_set_bit(_TRC_accessed, &trc->flags) )
+ printk(XENLOG_G_INFO "d%d: VIRIDIAN MSR_TIME_REF_COUNT: accessed\n",
+ d->domain_id);
- /* convert tsc to count of 100ns periods */
- set_time_scale(&tsc_to_ns, d->arch.tsc_khz * 1000ul);
- *val = scale_delta(tsc, &tsc_to_ns) / 100ul;
+ perfc_incr(mshv_rdmsr_time_ref_count);
+ *val = raw_trc_val(d) + trc->off;
break;
}
if ( !is_viridian_domain(d) )
return 0;
- ctxt.hypercall_gpa = d->arch.hvm_domain.viridian.hypercall_gpa.raw;
- ctxt.guest_os_id = d->arch.hvm_domain.viridian.guest_os_id.raw;
+ ctxt.time_ref_count = d->arch.hvm_domain.viridian.time_ref_count.val;
+ ctxt.hypercall_gpa = d->arch.hvm_domain.viridian.hypercall_gpa.raw;
+ ctxt.guest_os_id = d->arch.hvm_domain.viridian.guest_os_id.raw;
return (hvm_save_entry(VIRIDIAN_DOMAIN, 0, h, &ctxt) != 0);
}
{
struct hvm_viridian_domain_context ctxt;
- if ( hvm_load_entry(VIRIDIAN_DOMAIN, h, &ctxt) != 0 )
+ if ( hvm_load_entry_zeroextend(VIRIDIAN_DOMAIN, h, &ctxt) != 0 )
return -EINVAL;
- d->arch.hvm_domain.viridian.hypercall_gpa.raw = ctxt.hypercall_gpa;
- d->arch.hvm_domain.viridian.guest_os_id.raw = ctxt.guest_os_id;
+ d->arch.hvm_domain.viridian.time_ref_count.val = ctxt.time_ref_count;
+ d->arch.hvm_domain.viridian.hypercall_gpa.raw = ctxt.hypercall_gpa;
+ d->arch.hvm_domain.viridian.guest_os_id.raw = ctxt.guest_os_id;
return 0;
}
v->paused_for_shutdown = 1;
}
+ arch_domain_shutdown(d);
+
__domain_finalise_shutdown(d);
spin_unlock(&d->shutdown_lock);
return 0;
}
-void domain_pause(struct domain *d)
+static void do_domain_pause(struct domain *d,
+ void (*sleep_fn)(struct vcpu *v))
{
struct vcpu *v;
- ASSERT(d != current->domain);
-
atomic_inc(&d->pause_count);
for_each_vcpu( d, v )
- vcpu_sleep_sync(v);
+ sleep_fn(v);
+
+ arch_domain_pause(d);
}
-void domain_pause_nosync(struct domain *d)
+void domain_pause(struct domain *d)
{
- struct vcpu *v;
-
- atomic_inc(&d->pause_count);
+ ASSERT(d != current->domain);
+ do_domain_pause(d, vcpu_sleep_sync);
+}
- for_each_vcpu( d, v )
- vcpu_sleep_nosync(v);
+void domain_pause_nosync(struct domain *d)
+{
+ do_domain_pause(d, vcpu_sleep_nosync);
}
void domain_unpause(struct domain *d)
{
struct vcpu *v;
+ arch_domain_unpause(d);
+
if ( atomic_dec_and_test(&d->pause_count) )
for_each_vcpu( d, v )
vcpu_wake(v);
return hvm_funcs.get_shadow_gs_base(v);
}
+
+#define has_hvm_params(d) \
+ ((d)->arch.hvm_domain.params != NULL)
+
#define viridian_feature_mask(d) \
- ((d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN])
+ (has_hvm_params(d) ? (d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN] : 0)
#define is_viridian_domain(d) \
(is_hvm_domain(d) && (viridian_feature_mask(d) & HVMPV_base_freq))
+#define has_viridian_time_ref_count(d) \
+ (is_viridian_domain(d) && (viridian_feature_mask(d) & HVMPV_time_ref_count))
+
void hvm_hypervisor_cpuid_leaf(uint32_t sub_idx,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx);
} fields;
};
+struct viridian_time_ref_count
+{
+ unsigned long flags;
+
+#define _TRC_accessed 0
+#define TRC_accessed (1 << _TRC_accessed)
+#define _TRC_running 1
+#define TRC_running (1 << _TRC_running)
+
+ uint64_t val;
+ int64_t off;
+};
+
struct viridian_domain
{
union viridian_guest_os_id guest_os_id;
union viridian_hypercall_gpa hypercall_gpa;
+ struct viridian_time_ref_count time_ref_count;
};
int
int
viridian_hypercall(struct cpu_user_regs *regs);
+void viridian_time_ref_count_freeze(struct domain *d);
+void viridian_time_ref_count_thaw(struct domain *d);
+
#endif /* __ASM_X86_HVM_VIRIDIAN_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
struct hvm_viridian_domain_context {
uint64_t hypercall_gpa;
uint64_t guest_os_id;
+ uint64_t time_ref_count;
};
DECLARE_HVM_SAVE_TYPE(VIRIDIAN_DOMAIN, 15, struct hvm_viridian_domain_context);
void arch_domain_destroy(struct domain *d);
+void arch_domain_shutdown(struct domain *d);
+void arch_domain_pause(struct domain *d);
+void arch_domain_unpause(struct domain *d);
+
int arch_set_info_guest(struct vcpu *, vcpu_guest_context_u);
void arch_get_info_guest(struct vcpu *, vcpu_guest_context_u);